package main

import "fmt"

func main() {
	a1 := []int{1, 3, 5}
	s1 := a1[:]
	fmt.Println(s1, len(s1), cap(s1)) // 输出 [1 3 5] 3 3
	fmt.Printf("%p\n", s1)
	fmt.Println(s1[:1], s1[2:]) // 输出 [1] [5]
	s1 = append(s1[:1], s1[2:]...)
	fmt.Printf("%p\n", s1)
	fmt.Println(s1) // 输出[1 5]
	s1[0] = 100
	fmt.Println(a1) // 输出 [100 5 5]
	DeferClousreLoopV1()
	DeferClousreLoopV2()
	DeferClousreLoopV3()
}

/*
在这个例子中，s1 的初始值为 a1[:]，即 [1 3 5]。然后你执行了 s1 = append(s1[:1], s1[2:]...)，这等同于 s1 = append(s1[:1], 5)。由于要追加的元素个数大于当前底层数组的长度（1 > 2），所以 Go 会创建一个新的数组，将 s1 的前两个元素（1 和 5）复制到新数组中，然后将新元素 5 追加到新数组中。所以，s1 的值变成了 [1 5]。

虽然底层数组发生了变化，但是 s1 的内存地址并没有变，这是因为 Go 在创建新数组时，会尽量复用原数组的内存空间，所以新数组的内存地址可能会与原数组的内存地址相同。

总结一下，append 操作导致切片 s1 的底层数组发生了变化，但是 s1 的内存地址并没有变。
首先打印 s1，输出为 [1 5]，然后将 s1[0] 赋值为 100，此时 s1 的内容变为 [100 5]。但是由于 s1 和 a1 共享同一个底层数组，所以 a1 的内容也被修改为 [100 5 5]。

这是因为在 Go 中，切片操作实际上是在操作底层数组。当你通过切片修改元素时，实际上是在修改底层数组的对应元素。因此，切片操作具有“可见性”，即修改切片的一个元素，其他引用该切片的变量也会看到这个修改。

*/

func DeferClousreLoopV1() {
	for i := 0; i < 10; i++ {
		defer func() {
			fmt.Println(i)
		}() //10
	}
}

func DeferClousreLoopV2() {
	for i := 0; i < 10; i++ {
		defer func(i int) {
			fmt.Println(i) //9 8 7 6 5 4 3 2 1 0
		}(i)
	}
}

func DeferClousreLoopV3() {
	for i := 0; i < 10; i++ {
		j := 1
		defer func() {
			fmt.Println(j) //1 1 1 1 1 1 1 1 1
		}()
	}
}
